The attached patch:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 5 Aug 2005 08:59:41 +0000 (08:59 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 5 Aug 2005 08:59:41 +0000 (08:59 +0000)
1. Converts the shutdown driver and xend to use the store instead of
   control messages,

2. Includes Anthony's xenstore notification code, and

3. Changes xend so that sysrq's are no longer sent as "special case"
   shutdown messages.  Store keys are cheap, so making the sysrq
   delivery less obscure is good.

I think I have made all of the appropriate modifications to Xend, but
it is complex, so I may have missed something.  Comments are welcome.

Signed-off-by: Dan Smith <danms@us.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
linux-2.6-xen-sparse/arch/xen/kernel/reboot.c
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
linux-2.6-xen-sparse/include/asm-xen/xenbus.h
tools/python/xen/xend/XendClient.py
tools/python/xen/xend/XendDomain.py
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/server/SrvDomain.py
tools/python/xen/xm/sysrq.py

index e56e1edcee6732e8d04638f20fc0ff97540909d2..944700069085f524b7a2292f0b9606634f0b0850 100644 (file)
@@ -11,7 +11,6 @@ static int errno;
 #include <linux/sysrq.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
-#include <asm-xen/ctrl_if.h>
 #include <asm-xen/evtchn.h>
 #include <asm-xen/hypervisor.h>
 #include <asm-xen/xen-public/dom0_ops.h>
@@ -19,6 +18,11 @@ static int errno;
 #include <asm-xen/queues.h>
 #include <asm-xen/xenbus.h>
 
+#define SHUTDOWN_INVALID  -1
+#define SHUTDOWN_POWEROFF  0
+#define SHUTDOWN_REBOOT    1
+#define SHUTDOWN_SUSPEND   2
+
 void machine_restart(char * __unused)
 {
        /* We really want to get pending console data out before we die. */
@@ -53,7 +57,7 @@ EXPORT_SYMBOL(machine_power_off);
  */
 
 /* Ignore multiple shutdown requests. */
-static int shutting_down = -1;
+static int shutting_down = SHUTDOWN_INVALID;
 
 static void __do_suspend(void)
 {
@@ -126,8 +130,6 @@ static void __do_suspend(void)
 
     xenbus_suspend();
 
-    ctrl_if_suspend();
-
     irq_suspend();
 
     gnttab_suspend();
@@ -140,7 +142,7 @@ static void __do_suspend(void)
 
     HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
 
-    shutting_down = -1
+    shutting_down = SHUTDOWN_INVALID
 
     memcpy(&xen_start_info, &suspend_record->resume_info,
            sizeof(xen_start_info));
@@ -163,8 +165,6 @@ static void __do_suspend(void)
 
     irq_resume();
 
-    ctrl_if_resume();
-
     xenbus_resume();
 
 #ifdef CONFIG_SMP
@@ -204,7 +204,7 @@ static int shutdown_process(void *__unused)
 
     switch ( shutting_down )
     {
-    case CMSG_SHUTDOWN_POWEROFF:
+    case SHUTDOWN_POWEROFF:
         if ( execve("/sbin/poweroff", poweroff_argv, envp) < 0 )
         {
             sys_reboot(LINUX_REBOOT_MAGIC1,
@@ -214,7 +214,7 @@ static int shutdown_process(void *__unused)
         }
         break;
 
-    case CMSG_SHUTDOWN_REBOOT:
+    case SHUTDOWN_REBOOT:
         if ( execve("/sbin/reboot", restart_argv, envp) < 0 )
         {
             sys_reboot(LINUX_REBOOT_MAGIC1,
@@ -225,7 +225,7 @@ static int shutdown_process(void *__unused)
         break;
     }
 
-    shutting_down = -1; /* could try again */
+    shutting_down = SHUTDOWN_INVALID; /* could try again */
 
     return 0;
 }
@@ -234,7 +234,7 @@ static void __shutdown_handler(void *unused)
 {
     int err;
 
-    if ( shutting_down != CMSG_SHUTDOWN_SUSPEND )
+    if ( shutting_down != SHUTDOWN_SUSPEND )
     {
         err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES);
         if ( err < 0 )
@@ -246,42 +246,103 @@ static void __shutdown_handler(void *unused)
     }
 }
 
-static void shutdown_handler(ctrl_msg_t *msg, unsigned long id)
+static void shutdown_handler(struct xenbus_watch *watch, const char *node)
 {
     static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
 
-    if ( msg->subtype == CMSG_SHUTDOWN_SYSRQ )
-    {
-       int sysrq = ((shutdown_sysrq_t *)&msg->msg[0])->key;
-       
+    int type = -1;
+
+    if (!xenbus_scanf("control", "shutdown", "%i", &type)) {
+        printk("Unable to read code in control/shutdown\n");
+        return;
+    };
+
+    xenbus_printf("control", "shutdown", "%i", SHUTDOWN_INVALID);
+
+    if ((type == SHUTDOWN_POWEROFF) ||
+        (type == SHUTDOWN_REBOOT)   ||
+        (type == SHUTDOWN_SUSPEND)) {
+        shutting_down = type;
+        schedule_work(&shutdown_work);
+    }
+
+}
+
 #ifdef CONFIG_MAGIC_SYSRQ
+static void sysrq_handler(struct xenbus_watch *watch, const char *node)
+{
+    char sysrq_key = '\0';
+    
+    if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) {
+        printk("Unable to read sysrq code in control/sysrq\n");
+        return;
+    }
+
+    xenbus_printf("control", "sysrq", "%c", '\0');
+
+    if (sysrq_key != '\0') {
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-       handle_sysrq(sysrq, NULL, NULL);
+        handle_sysrq(sysrq_key, NULL, NULL);
 #else
-       handle_sysrq(sysrq, NULL, NULL, NULL);
-#endif
+        handle_sysrq(sysrq_key, NULL, NULL, NULL);
 #endif
     }
-    else if ( (shutting_down == -1) &&
-         ((msg->subtype == CMSG_SHUTDOWN_POWEROFF) ||
-          (msg->subtype == CMSG_SHUTDOWN_REBOOT) ||
-          (msg->subtype == CMSG_SHUTDOWN_SUSPEND)) )
-    {
-        shutting_down = msg->subtype;
-        schedule_work(&shutdown_work);
+}
+#endif
+
+static struct xenbus_watch shutdown_watch = {
+    .node = "control/shutdown",
+    .callback = shutdown_handler
+};
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static struct xenbus_watch sysrq_watch = {
+    .node ="control/sysrq",
+    .callback = sysrq_handler
+};
+#endif
+
+static struct notifier_block xenstore_notifier;
+
+static int setup_shutdown_watcher(struct notifier_block *notifier,
+                                  unsigned long event,
+                                  void *data)
+{
+    int err1=0, err2=0;
+
+    down(&xenbus_lock);
+    err1 = register_xenbus_watch(&shutdown_watch);
+#ifdef CONFIG_MAGIC_SYSRQ
+    err2 = register_xenbus_watch(&sysrq_watch);
+#endif
+    up(&xenbus_lock);
+
+    if (err1) {
+        printk("Failed to set shutdown watcher\n");
     }
-    else
-    {
-        printk("Ignore spurious shutdown request\n");
+    
+#ifdef CONFIG_MAGIC_SYSRQ
+    if (err2) {
+        printk("Failed to set sysrq watcher\n");
     }
+#endif
 
-    ctrl_if_send_response(msg);
+    return NOTIFY_STOP;
 }
 
 static int __init setup_shutdown_event(void)
 {
-    ctrl_if_register_receiver(CMSG_SHUTDOWN, shutdown_handler, 0);
+    
+    xenstore_notifier.notifier_call = setup_shutdown_watcher;
+
+    if (xen_start_info.store_evtchn) {
+        setup_shutdown_watcher(&xenstore_notifier, 0, NULL);
+    } else {
+        register_xenstore_notifier(&xenstore_notifier);
+    }
+    
     return 0;
 }
 
-__initcall(setup_shutdown_event);
+subsys_initcall(setup_shutdown_event);
index d440618f2d7a7e9ab695c308013e840a6d64ea5c..706d351121ae2314e7effeb54902ca9a2754bd09 100644 (file)
 #include <linux/ctype.h>
 #include <linux/fcntl.h>
 #include <stdarg.h>
+#include <linux/notifier.h>
 #include "xenbus_comms.h"
 
 #define streq(a, b) (strcmp((a), (b)) == 0)
 
+/* Protects notifier chain */
+DECLARE_MUTEX(xenstore_control);
+
+static struct notifier_block *xenstore_chain;
+
 /* If something in array of ids matches this device, return it. */
 static const struct xenbus_device_id *
 match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
@@ -309,6 +315,26 @@ void xenbus_resume(void)
        up(&xenbus_lock);
 }
 
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+       int ret;
+
+       if ((ret = down_interruptible(&xenstore_control)) != 0) 
+               return ret;
+       ret = notifier_chain_register(&xenstore_chain, nb);
+       up(&xenstore_control);
+       return ret;
+}
+EXPORT_SYMBOL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+       down(&xenstore_control);
+       notifier_chain_unregister(&xenstore_chain, nb);
+       up(&xenstore_control);
+}
+EXPORT_SYMBOL(unregister_xenstore_notifier);
+
 /* called from a thread in privcmd/privcmd.c */
 int do_xenbus_probe(void *unused)
 {
@@ -323,6 +349,15 @@ int do_xenbus_probe(void *unused)
                return err;
        }
 
+       err = notifier_call_chain(&xenstore_chain, 0, 0);
+       if (err == NOTIFY_BAD) {
+               printk("%s: calling xenstore notify chain failed\n",
+                      __FUNCTION__);
+               return -EINVAL;
+       }
+
+       err = 0;
+
        /* Initialize non-xenbus drivers */
        balloon_init_watcher();
 
index af205d8945a65157d450c1a880a749b3568a960d..0f30dc8ebe98fcfe2b568d38de3f39bb2cb26122 100644 (file)
@@ -29,6 +29,7 @@
  * IN THE SOFTWARE.
  */
 #include <linux/device.h>
+#include <linux/notifier.h>
 #include <asm/semaphore.h>
 
 /* A xenbus device. */
@@ -112,6 +113,10 @@ struct xenbus_watch
        void (*callback)(struct xenbus_watch *, const char *node);
 };
 
+/* notifer routines for when the xenstore comes up */
+int register_xenstore_notifier(struct notifier_block *nb);
+void unregister_xenstore_notifier(struct notifier_block *nb);
+
 int register_xenbus_watch(struct xenbus_watch *watch);
 void unregister_xenbus_watch(struct xenbus_watch *watch);
 
index 868836c30fa932cc44763121212d30b2f0b681a4..570c59d23196fdcf9f7d805a4abbb9a4dd8303e9 100644 (file)
@@ -208,11 +208,15 @@ class Xend:
         return self.xendPost(self.domainurl(id),
                              {'op'      : 'pause' })
 
-    def xend_domain_shutdown(self, id, reason, key=0):
+    def xend_domain_shutdown(self, id, reason):
         return self.xendPost(self.domainurl(id),
                              {'op'      : 'shutdown',
-                              'reason'  : reason,
-                              'key'     : key })
+                              'reason'  : reason})
+
+    def xend_domain_sysrq(self, id, key):
+        return self.xendPost(self.domainurl(id),
+                             {'op'      : 'sysrq',
+                              'key'     : key})
 
     def xend_domain_destroy(self, id, reason):
         return self.xendPost(self.domainurl(id),
index 157d2216cfba4f8f5cf5e91143ca72259bf0cc39..6527f3fb5fe522767f340958a81e91405dd677a3 100644 (file)
@@ -386,7 +386,7 @@ class XendDomain:
         except Exception, ex:
             raise XendError(str(ex))
     
-    def domain_shutdown(self, id, reason='poweroff', key=0):
+    def domain_shutdown(self, id, reason='poweroff'):
         """Shutdown domain (nicely).
          - poweroff: restart according to exit code and restart mode
          - reboot:   restart on exit
@@ -402,11 +402,18 @@ class XendDomain:
         eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason])
         if reason == 'halt':
             reason = 'poweroff'
-        val = dominfo.shutdown(reason, key=key)
-        if not reason in ['suspend', 'sysrq']:
+        val = dominfo.shutdown(reason)
+        if not reason in ['suspend']:
             self.domain_shutdowns()
         return val
 
+    def domain_sysrq(self, id, key):
+        """Send a SysRq to a domain
+        """
+        dominfo = self.domain_lookup(id)
+        val = dominfo.send_sysrq(key)
+        return val
+
     def domain_shutdowns(self):
         """Process pending domain shutdowns.
         Destroys domains whose shutdowns have timed out.
index 3e016b681f7b845441a4f5c54225f153e54c07ef..3510f79441309666bbfa595b889ba43c5f756d4a 100644 (file)
@@ -52,13 +52,12 @@ shutdown_reasons = {
     DOMAIN_CRASH   : "crash",
     }
 
-"""Map shutdown reasons to the message type to use.
+"""Map shutdown reasons to codes
 """
-shutdown_messages = {
-    'poweroff' : 'shutdown_poweroff_t',
-    'reboot'   : 'shutdown_reboot_t',
-    'suspend'  : 'shutdown_suspend_t',
-    'sysrq'    : 'shutdown_sysrq_t',
+shutdown_codes = {
+    'poweroff' : DOMAIN_POWEROFF,
+    'reboot'   : DOMAIN_REBOOT,
+    'suspend'  : DOMAIN_SUSPEND,
     }
 
 RESTART_ALWAYS   = 'always'
@@ -152,8 +151,6 @@ class XendDomainInfo:
         vm = cls(db)
         vm.construct(config)
         vm.saveToDB(sync=True)
-        # Flush info to xenstore immediately
-        vm.exportToDB()
 
         return vm
 
@@ -941,19 +938,20 @@ class XendDomainInfo:
 
             self.channel.writeRequest(msg)
 
-    def shutdown(self, reason, key=0):
-        msgtype = shutdown_messages.get(reason)
-        if not msgtype:
+    def shutdown(self, reason):
+        reasonid = shutdown_codes.get(reason)
+        if reasonid == None:
             raise XendError('invalid reason:' + reason)
-        extra = {}
-        if reason == 'sysrq':
-            extra['key'] = key
-        if self.channel:
-            msg = messages.packMsg(msgtype, extra)
-            self.channel.writeRequest(msg)
-        if not reason in ['suspend', 'sysrq']:
-            self.shutdown_pending = {'start':time.time(), 'reason':reason,
-                                     'key':key}
+        db = self.db.addChild("/control");
+        db['shutdown'] = '%i' % reasonid;
+        db.saveDB(save=True);
+        if not reason in ['suspend']:
+            self.shutdown_pending = {'start':time.time(), 'reason':reason}
+
+    def send_sysrq(self, key=0):
+        db = self.db.addChild("/control");
+        db['sysrq'] = '%c' % key;
+        db.saveDB(save=True);        
 
     def shutdown_time_left(self, timeout):
         if not self.shutdown_pending:
index 6e51e6951875c9591cf1b80c47056933ae87b5ed..d0249dab7bd64a2afc703875f92a98385f114214 100644 (file)
@@ -39,13 +39,21 @@ class SrvDomain(SrvDir):
     def op_shutdown(self, op, req):
         fn = FormFn(self.xd.domain_shutdown,
                     [['dom',    'int'],
-                     ['reason', 'str'],
-                     ['key',    'int']])
+                     ['reason', 'str']])
         val = fn(req.args, {'dom': self.dom.id})
         req.setResponseCode(http.ACCEPTED)
         req.setHeader("Location", "%s/.." % req.prePathURL())
         return val
 
+    def op_sysrq(self, op, req):
+        fn = FormFn(self.xd.domain_sysrq,
+                    [['dom',    'int'],
+                     ['key',    'int']])
+        val = fn(req.args, {'dom' : self.dom.id})
+        req.setResponseCode(http.ACCEPTED)
+        req.setHeader("Location", "%s/.." % req.prePathURL())
+        return val
+
     def op_destroy(self, op, req):
         fn = FormFn(self.xd.domain_destroy,
                     [['dom',    'int'],
index 44827af094f16d25ef1a0565d25678499faa6a0f..12b2da22fe6808b4c6fc3e93c00f17920cd31e57 100644 (file)
@@ -21,9 +21,6 @@ gopts.opt('help', short='h',
          fn=set_true, default=0,
          use="Print this help.")
 
-def sysrq(dom, req):
-    server.xend_domain_shutdown(dom, 'sysrq', req)
-
 def main(argv):
     opts = gopts
     args = opts.parse(argv)
@@ -36,4 +33,4 @@ def main(argv):
     if len(args) < 2: opts.err('Missing sysrq character')
     dom = args[0]
     req = ord(args[1][0])
-    sysrq(dom, req)
+    server.xend_domain_sysrq(dom, req)